package com.begamer.card.common.dao.hibernate;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.Map.Entry;

import org.apache.log4j.Logger;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.begamer.card.common.dao.GenericDao;
import com.begamer.card.common.dao.HqlParameter;
import com.begamer.card.common.dao.finder.FinderArgumentTypeFactory;
import com.begamer.card.common.dao.finder.FinderExecutor;
import com.begamer.card.common.dao.finder.FinderNamingStrategy;
import com.begamer.card.common.dao.finder.impl.SimpleFinderArgumentTypeFactory;
import com.begamer.card.common.dao.finder.impl.SimpleFinderNamingStrategy;

public class GenericDaoHibernate<T, PK extends Serializable> extends
		HibernateDaoSupport implements GenericDao<T, PK>, FinderExecutor<T> {
	private static final Logger logger = Logger
			.getLogger(GenericDaoHibernate.class);

	private Class<T> type;

	private FinderNamingStrategy namingStrategy = new SimpleFinderNamingStrategy(); // Default.
	// Can
	// override
	// in
	// config
	private FinderArgumentTypeFactory argumentTypeFactory = new SimpleFinderArgumentTypeFactory(); // Default.

	// Can
	// override
	// in
	// config

	public GenericDaoHibernate(Class<T> type) {
		this.type = type;
	}

	@SuppressWarnings("unchecked")
	public PK create(T o) {
		// return (PK) getHibernateTemplate().save(o);
		Session session = this.getSession();
		Transaction tx = session.beginTransaction();
		logger.debug("create	-	class name:" + o.getClass().getName());
		try {
			return (PK) session.save(o);
		} catch (Exception e) {
			logger.error(e.toString());
		} finally {
			tx.commit();
			session.close();
		}
		return null;
	}

	public PK hibCreate(T o) {
		return (PK) getHibernateTemplate().save(o);
	}

	@SuppressWarnings("unchecked")
	public T read(PK id) {
		return (T) getHibernateTemplate().get(type, id);
	}

	public void hibUpdate(T o) {
		getHibernateTemplate().update(o);
	}

	public void update(T o) {
		// getHibernateTemplate().update(o);
		Session session = this.getSession();
		Transaction tx = session.beginTransaction();
		try {
			session.update(o);
		} catch (Exception e) {
			logger.error(e.toString());
		} finally {
			tx.commit();
			session.close();
		}
	}

	public void updateWithoutLog(T o) {
		Session session = this.getSession();
		Transaction tx = session.beginTransaction();
		try {
			session.update(o);
		} catch (Exception e) {
			logger.error(e.toString());
		} finally {
			tx.commit();
			session.close();
		}
	}

	public void delete(T o) {
		getHibernateTemplate().delete(o);
	}

	public int executeUpdate(String hql) {

		Session session = this.getSession();
		Transaction tx = session.beginTransaction();
		try {
			return session.createQuery(hql).executeUpdate();
		} catch (DataAccessResourceFailureException e) {
			logger.error(e.toString());
		} catch (HibernateException e) {
			logger.error(e.toString());
		} catch (IllegalStateException e) {
			logger.error(e.toString());
		} finally {
			tx.commit();
			session.close();
		}
		return -1;
	}

	public int executeSqlUpdate(String sql) {
		Session session = this.getSession();
		Transaction tx = session.beginTransaction();
		try {
			return session.createSQLQuery(sql).executeUpdate();
		} catch (DataAccessResourceFailureException e) {
			logger.error(e.toString());
		} catch (HibernateException e) {
			logger.error(e.toString());
		} catch (IllegalStateException e) {
			logger.error(e.toString());
		} finally {
			tx.commit();
			session.close();
		}
		return -1;
	}

	// where参数是“where”之后的字符串，可以为空或者“”；
	public int executeUpdateProperties(Set<Entry<String, String>> propSet,
			String where) {
		if (propSet != null && propSet.size() > 0) {
			StringBuffer update = new StringBuffer();
			update.append("update ");
			update.append(type.getSimpleName());
			update.append(" set ");

			Iterator iterator = propSet.iterator();

			if (iterator.hasNext()) {
				Entry<String, String> entry = (Entry<String, String>) iterator
						.next();
				String propName = entry.getKey();
				String propValue = entry.getValue();
				update.append(propName);
				update.append("=");
				update.append(propValue);
			}

			while (iterator.hasNext()) {
				Entry<String, String> entry = (Entry<String, String>) iterator
						.next();
				String propName = entry.getKey();
				String propValue = entry.getValue();
				update.append(",");
				update.append(propName);
				update.append("=");
				update.append(propValue);
			}

			if (where != null && !where.trim().equals("")) {
				update.append(" where ");
				update.append(where);
			}
			logger.debug("executeUpdateProperties	-	update sql string:"
					+ update.toString());
			return executeUpdate(update.toString());
		}
		return -1;
	}

	@SuppressWarnings("unchecked")
	public List<T> loadByProperty(String propertyName, Object value) {
		if (logger.isDebugEnabled())
			logger.debug("loadByProperty " + type.getSimpleName() + " : "
					+ propertyName + ", value: " + value);

		String queryString = "from " + type.getSimpleName()
				+ " as model where model." + propertyName + "= ?";
		List<T> list = getHibernateTemplate().find(queryString, value);
		return list;
	}

	@SuppressWarnings("unchecked")
	public List<T> load(final int index, final int count, String where,
			String orderby) {
		if (logger.isDebugEnabled())
			logger.debug("index:" + index + ",count:" + count + ",where:"
					+ where + ",orderby:" + orderby);

		if (where == null || where == "")
			where = "";
		else
			where = "where "
					+ where.replace(',', '=').replace(";", " and ").replace(
							"|", " or ").replace("!", "<>");

		if (orderby == null || orderby == "")
			orderby = "order by id desc";
		else
			orderby = "order by " + orderby.replace(';', ' ');

		final String queryString = "from " + type.getSimpleName() + " " + where
				+ " " + orderby;
		logger.debug("queryString:" + queryString);
		List<T> list = getHibernateTemplate().executeFind(
				new HibernateCallback() {
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Query queryObject = session.createQuery(queryString);
						if (count != 0) {
							queryObject.setFirstResult(index);
							queryObject.setMaxResults(count);
						}
						return queryObject.list();
					}
				});
		return list;
	}

	@SuppressWarnings("unchecked")
	public List<T> loadWithParameterType(final int index, final int count,
			String where, String orderby, final List<HqlParameter> parameters) {
		if (logger.isDebugEnabled())
			logger.debug("index:" + index + ",count:" + count + ",where:"
					+ where + ",orderby:" + orderby);

		if (where == null || where == "")
			where = "";
		else
			where = "where "
					+ where.replace(',', '=').replace(";", " and ").replace(
							"|", " or ").replace("!", "<>");

		if (orderby == null || orderby == "")
			orderby = "order by id desc";
		else
			orderby = "order by " + orderby.replace(';', ' ');

		final String queryString = "from " + type.getSimpleName() + " " + where
				+ " " + orderby;
		logger.debug("queryString:" + queryString);
		List<T> list = getHibernateTemplate().executeFind(
				new HibernateCallback() {
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Query queryObject = session.createQuery(queryString);
						if (parameters != null && parameters.size() > 0) {
							Iterator<HqlParameter> iter = parameters.iterator();
							while (iter.hasNext()) {
								HqlParameter parameter = iter.next();
								queryObject.setParameter(parameter.getName(),
										parameter.getValue(), parameter
												.getType());
								logger.debug("name:" + parameter.getName());
								logger.debug("value:" + parameter.getValue());
								logger.debug("type:" + parameter.getType());
							}
						}

						if (count != 0) {
							queryObject.setFirstResult(index);
							queryObject.setMaxResults(count);
						}
						return queryObject.list();
					}
				});
		return list;
	}

	@SuppressWarnings("unchecked")
	public List<T> loadHqlPure(final int index, final int count, String hql) {
		if (logger.isDebugEnabled())
			logger.debug("index:" + index + ",count:" + count + ",hql:" + hql);

		if (hql == null || hql == "")
			hql = "";
		// else hql = hql.replace(',','=').replace(";"," and ").replace("|"," or
		// ").replace("!","<>");

		final String queryString = hql;

		List<T> list = getHibernateTemplate().executeFind(
				new HibernateCallback() {
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Query queryObject = session.createQuery(queryString);
						if (count != 0) {
							queryObject.setFirstResult(index);
							queryObject.setMaxResults(count);
						}
						return queryObject.list();
					}
				});

		return list;
	}

	@SuppressWarnings("unchecked")
	public Long count(String where) {
		if (where == null || where.length() == 0)
			where = "";
		else
			where = "where "
					+ where.replace(',', '=').replace(";", " and ").replace(
							"|", " or ");

		final String queryString = "select count(id) from "
				+ type.getSimpleName() + " " + where;
		if (logger.isDebugEnabled())
			logger.debug("queryString:" + queryString);

		List list = getHibernateTemplate().executeFind(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Query queryObject = session.createQuery(queryString);
				return queryObject.list();
			}
		});

		return (Long) list.get(0);
	}

	public Long countGroup(String where) {
		if (where == null || where.length() == 0)
			where = "";
		else
			where = "where "
					+ where.replace(',', '=').replace(";", " and ").replace(
							"|", " or ");

		final String queryString = "select count(count(contentid)) from "
				+ type.getSimpleName() + " " + where;
		if (logger.isDebugEnabled())
			logger.debug("queryString:" + queryString);

		List list = getHibernateTemplate().executeFind(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Query queryObject = session.createQuery(queryString);
				return queryObject.list();
			}
		});

		return (Long) list.get(0);
	}

	// guo shi add
	@SuppressWarnings("unchecked")
	public List<Integer> loadByGroup(final int index, final int count,
			String where, String orderby) {
		if (logger.isDebugEnabled())
			logger.debug("index:" + index + ",count:" + count + ",where:"
					+ where + ",orderby:" + orderby);

		if (where == null || where == "")
			where = "";
		else
			where = "where "
					+ where.replace(',', '=').replace(";", " and ").replace(
							"|", " or ").replace("!", "<>");

		if (orderby == null || orderby == "")
			orderby = "order by id desc";
		else
			orderby = "order by " + orderby.replace(';', ' ');

		final String queryString = "select content.id from "
				+ type.getSimpleName() + " " + where;// + "
		// " +
		// orderby;
		logger.debug("queryString:" + queryString);
		List<Integer> list = getHibernateTemplate().executeFind(
				new HibernateCallback() {
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Query queryObject = session.createQuery(queryString);
						if (count != 0) {
							queryObject.setFirstResult(index);
							queryObject.setMaxResults(count);
						}
						return queryObject.list();
					}
				});
		return list;
	}

	public Long countRecommend(String where) {
		if (where == null || where.length() == 0)
			where = "";
		else
			where = where.replace(";", " and ").replace("|", " or ");

		final String queryString = "select count(id) from "
				+ type.getSimpleName() + " " + where;
		if (logger.isDebugEnabled())
			logger.debug("queryString:" + queryString);

		List list = getHibernateTemplate().executeFind(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Query queryObject = session.createQuery(queryString);
				return queryObject.list();
			}
		});

		return (Long) list.get(0);
	}

	@SuppressWarnings("unchecked")
	public Long countSql(String sql) {
		if (sql == null)
			sql = "";

		final String queryString = "select count(id) from "
				+ type.getSimpleName() + " " + sql;
		if (logger.isDebugEnabled())
			logger.debug("queryString:" + queryString);

		List list = getHibernateTemplate().executeFind(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Query queryObject = session.createQuery(queryString);
				return queryObject.list();
			}
		});

		return (Long) list.get(0);
	}

	@SuppressWarnings("unchecked")
	public Long countSqlPure(String sql) {
		if (sql == null)
			sql = "";

		final String queryString = sql;
		if (logger.isDebugEnabled())
			logger.debug("queryString:" + queryString);

		List list = getHibernateTemplate().executeFind(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Query queryObject = session.createSQLQuery(queryString);
				return queryObject.list();
			}
		});

		return (Long) list.get(0);
	}

	@SuppressWarnings("unchecked")
	public Long countHqlPure(String hql) {
		if (hql == null)
			hql = "";

		final String queryString = hql;
		if (logger.isDebugEnabled())
			logger.debug("queryString:" + queryString);

		List list = getHibernateTemplate().executeFind(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Query queryObject = session.createQuery(queryString);
				return queryObject.list();
			}
		});
		if (logger.isDebugEnabled()) {
			logger.debug("list:" + list);
		}
		if (list == null || list.size() == 0) {
			return Long.valueOf(0);
		}

		return (Long) list.get(0);
	}

	@SuppressWarnings("unchecked")
	public List<T> loadSql(final int index, final int count, String sql) {
		if (logger.isDebugEnabled())
			logger.debug("index:" + index + ",count:" + count + ",sql:" + sql);

		if (sql == null)
			sql = "";

		final String queryString = "from " + type.getSimpleName() + " " + sql;
		logger.debug("loadSql	-	queryString:" + queryString);

		List<T> list = getHibernateTemplate().executeFind(
				new HibernateCallback() {
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Query queryObject = session.createQuery(queryString);
						if (count != 0) {
							queryObject.setFirstResult(index);
							queryObject.setMaxResults(count);
						}
						return queryObject.list();
					}
				});

		return list;
	}

	@SuppressWarnings("unchecked")
	public List<T> executeFinder(Method method, final Object[] queryArgs) {
		final String queryName = getNamingStrategy().queryNameFromMethod(type,
				method);

		boolean checkWriteOperation = this.getHibernateTemplate()
				.isCheckWriteOperations();
		int flushMode = this.getHibernateTemplate().getFlushMode();

		getHibernateTemplate().setCheckWriteOperations(false);
		getHibernateTemplate()
				.setFlushMode(
						org.springframework.orm.hibernate3.HibernateAccessor.FLUSH_NEVER);

		List<T> list = getHibernateTemplate().findByNamedQuery(queryName,
				queryArgs);

		getHibernateTemplate().setCheckWriteOperations(checkWriteOperation);
		getHibernateTemplate().setFlushMode(flushMode);

		return list;
	}

	public FinderNamingStrategy getNamingStrategy() {
		return namingStrategy;
	}

	public void setNamingStrategy(FinderNamingStrategy namingStrategy) {
		this.namingStrategy = namingStrategy;
	}

	public FinderArgumentTypeFactory getArgumentTypeFactory() {
		return argumentTypeFactory;
	}

	public void setArgumentTypeFactory(
			FinderArgumentTypeFactory argumentTypeFactory) {
		this.argumentTypeFactory = argumentTypeFactory;

	}

	public Session HibSession() {
		return this.getSession();
	}

/**
	 * 根据自己写的hql查询
	 * lt@2013-12-2 下午04:23:59
	 * @param hql
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<T> loadByHql(String hql)
	{
		Session session=getSession();
		try
		{
			Query query=session.createQuery(hql);
			List<T> list=query.list();
			return list;
		} 
		catch (Exception e)
		{
			e.printStackTrace();
			return null;
		}
		finally
		{
			session.close();
		}
	}

}
